﻿
namespace TransportAnalizer.AppTests.UnitTests
{
    using System.Collections.Generic;
    using System.Linq;
    using System.Windows;
    using System.Data;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using Moq;
    using TransportAnalizer_2._0.ViewModels;
    using TransportAnalizer_2._0.Model;
    using TransportAnalizer.DataTests;
    using TransportAnalizer.HelpClasses;


    [TestClass]
    public class NodeViewModelTests
    {
        private Mock<IBusinessContextFactory> mock;
        private List<Node> store;

        [TestInitialize]
        public void TestInitialize()
        {
            store = new List<Node>();

            mock = new Mock<IBusinessContextFactory>();
            mock.Setup(m => m.GetNodeBusinessContext.GetNodeList()).Returns(store);
            mock.Setup(m => m.GetNodeBusinessContext.CreateNode(It.IsAny<Node>())).Callback<Node>(node => store.Add(node));
            mock.Setup(m => m.GetNodeBusinessContext.DeleteNode(It.IsAny<Node>())).Callback<Node>(node => store.Remove(node));
            mock.Setup(m => m.GetNodeBusinessContext.UpdateNode(It.IsAny<Node>())).Callback<Node>(node =>
            {
                int i = store.IndexOf(node);
                store[i] = node;
            });
        }

        [TestMethod]
        public void IsViewModel()
        {
            Assert.IsTrue(typeof(NodeViewModel).BaseType == typeof(ViewModel));
        }

        [TestMethod]
        public void AddCommand_CannotExecuteWhenLocationIsNotValid()
        {
            var viewModel = new NodeViewModel(mock.Object)
            {
                SelectedNode = new Node
                {
                    Location=null
                }
            };

            Assert.IsFalse(viewModel.AddCommand.CanExecute(null));
        }


        [TestMethod]
        public void AddCommand_AddsNodeToNodesCollectionWhenExecutedSuccessfully()
        {
            var viewModel = new NodeViewModel(mock.Object)
            {
                SelectedNode = new Node
                {
                    Location = System.Data.Entity.Spatial.DbGeography.FromText("POINT(-122.206834 57.611421)")
                }
            };

            viewModel.AddCommand.Execute(null);

            Assert.IsTrue(viewModel.Nodes.Count == 1);
        }

        [TestMethod]
        public void CanModify_ShouldEqualFalseWhenSelectedNodeIsNull()
        {
            var viewModel = new NodeViewModel(mock.Object) { SelectedNode = null };
            Assert.IsFalse(viewModel.CanModify);
        }

        [TestMethod]
        public void CanModify_ShouldEqualTrueWhenSelectedNodeIsNotNull()
        {
            var viewModel = new NodeViewModel(mock.Object) { SelectedNode = new Node() };
            Assert.IsTrue(viewModel.CanModify);
        }

        [TestMethod]
        public void GetNodeListCommand_PopulatesNodesPropertyWithExpectedCollectionFromDataStore()
        {
            mock.Object.GetNodeBusinessContext.CreateNode(new Node { Location = System.Data.Entity.Spatial.DbGeography.FromText("POINT(-123.206834 57.611421)") });
            mock.Object.GetNodeBusinessContext.CreateNode(new Node { Location = System.Data.Entity.Spatial.DbGeography.FromText("POINT(-124.206834 57.611421)") });
            mock.Object.GetNodeBusinessContext.CreateNode(new Node { Location = System.Data.Entity.Spatial.DbGeography.FromText("POINT(-121.206834 57.611421)") });

            var viewModel = new NodeViewModel(mock.Object);

            viewModel.GetNodeListCommand.Execute(null);

            Assert.IsTrue(viewModel.Nodes.Count == 3);

            // Use CollectionAssert by overriding Equals in entities
            // or using IComparer in CollectionAssert for a more full-proof
            // solution
        }

        [TestMethod]
        public void GetNodeListCommand_SelectedNodeIsSetToNullWhenExecuted()
        {
            var viewModel = new NodeViewModel(mock.Object)
            {
                SelectedNode = new Node
                {
                    Location = System.Data.Entity.Spatial.DbGeography.FromText("POINT(-122.206834 57.611421)")
                }
            };

            viewModel.GetNodeListCommand.Execute(null);

            Assert.IsNull(viewModel.SelectedNode);
        }

        [TestMethod]
        public void SaveCommand_InvokesIBusinessContextUpdateNodeMethod()
        {
            // Arrange
            mock.Object.GetNodeBusinessContext.CreateNode(new Node { Location = System.Data.Entity.Spatial.DbGeography.FromText("POINT(-122.206834 57.611421)") });

            var viewModel = new NodeViewModel(mock.Object);

            viewModel.GetNodeListCommand.Execute(null);
            viewModel.SelectedNode = viewModel.Nodes.First();

            // Act
            viewModel.UpdateCommand.Execute(null);

            // Assert
            mock.Verify(m => m.GetNodeBusinessContext.UpdateNode(It.IsAny<Node>()), Times.Once);
        }

        [TestMethod]
        public void DeleteCommand_InvokesIBusinessContextDeleteNodeMethod()
        {
            // Arrange
            mock.Object.GetNodeBusinessContext.CreateNode(new Node { Location = System.Data.Entity.Spatial.DbGeography.FromText("POINT(-122.206834 57.611421)") });

            var viewModel = new NodeViewModel(mock.Object);

            viewModel.GetNodeListCommand.Execute(null);
            viewModel.SelectedNode = viewModel.Nodes.First();

            // Act
            viewModel.DeleteCommand.Execute(null);

            // Assert
            mock.Verify(m => m.GetNodeBusinessContext.DeleteNode(It.IsAny<Node>()), Times.Once);
        }

        [TestMethod]
        public void DeleteCommand_SelectedNodeIsSetToNull()
        {
            // Arrange
            mock.Object.GetNodeBusinessContext.CreateNode(new Node { Location = System.Data.Entity.Spatial.DbGeography.FromText("POINT(-122.206834 57.611421)") });

            var viewModel = new NodeViewModel(mock.Object);

            viewModel.GetNodeListCommand.Execute(null);
            viewModel.SelectedNode = viewModel.Nodes.First();

            // Act
            viewModel.DeleteCommand.Execute(null);

            // Assert
            Assert.IsNull(viewModel.SelectedNode);
        }

        [TestMethod]
        public void PropertyChanged_IsRaisedForCanModifyWhenSelectedNodePropertyHasChanged()
        {
            var viewModel = new NodeViewModel(mock.Object);

            bool eventRaised = false;

            viewModel.PropertyChanged += (sender, e) =>
            {
                if (e.PropertyName == "CanModify")
                    eventRaised = true;
            };

            viewModel.SelectedNode = null;

            Assert.IsTrue(eventRaised);
        }

        [TestMethod]
        public void PropertyChanged_IsRaisedForSelectedNodeWhenSelectedNodePropertyHasChanged()
        {
            var viewModel = new NodeViewModel(mock.Object);

            bool eventRaised = false;

            viewModel.PropertyChanged += (sender, e) =>
            {
                if (e.PropertyName == "SelectedNode")
                    eventRaised = true;
            };

            viewModel.SelectedNode = null;

            Assert.IsTrue(eventRaised);
        }
    }
}
